namespace SimpleWebServices.Globalization
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using Xunit;

    public sealed class LanguageFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Language>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .Serializable()
                .Implements<IComparable>()
                .Implements<IComparable<Language>>()
                .Implements<IEquatable<Language>>()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Language());
        }

        [Fact]
        public void ctor_string()
        {
            Assert.NotNull(new Language("en"));
        }

        [Fact]
        public void ctor_stringCulture()
        {
            Assert.NotNull(new Language("en-GB"));
        }

        [Fact]
        public void ctor_stringEmpty()
        {
            Assert.NotNull(new Language(string.Empty));
        }

        [Fact]
        public void ctor_stringInvalid()
        {
            Assert.Throws<FormatException>(() => new Language("not-a-language"));
        }

        [Fact]
        public void ctor_stringNull()
        {
            Assert.NotNull(new Language(null as string));
        }

        [Fact]
        public void ctor_SerializationInfo_StreamingContext()
        {
            Language expected = new Language("en");
            Language actual = null;

            using (Stream stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, new Language("en"));
                stream.Position = 0;
                actual = (Language)formatter.Deserialize(stream);
            }

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void prop_Invariant_get()
        {
            Language expected = CultureInfo.InvariantCulture;
            Language actual = Language.Invariant;

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void prop_Length()
        {
            Assert.True(new PropertyExpectations(typeof(Language).GetProperty("Length"))
                .TypeIs<int>()
                .DefaultValueIs(0)
                .Result);
        }

        [Fact]
        public void prop_Length_get()
        {
            int expected = 2;
            int actual = new Language("en").Length;

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void opEquality_Language_CultureInfo()
        {
            Language obj = new Language("en");
            CultureInfo comparand = new CultureInfo("en");

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_Language_CultureInfoDiffers()
        {
            Language obj = new Language("en");
            CultureInfo comparand = new CultureInfo("fr");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_LanguageNull_CultureInfo()
        {
            Language obj = null;
            CultureInfo comparand = new CultureInfo("en");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Language_CultureInfoNull()
        {
            Language obj = new Language("en");
            CultureInfo comparand = null;

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opInequality_Language_CultureInfo()
        {
            Language obj = new Language("en");
            CultureInfo comparand = new CultureInfo("en");

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_Language_CultureInfoDiffers()
        {
            Language obj = new Language("en");
            CultureInfo comparand = new CultureInfo("fr");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_LanguageNull_CultureInfo()
        {
            Language obj = null;
            CultureInfo comparand = new CultureInfo("en");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Language_CultureInfoNull()
        {
            Language obj = new Language("en");
            CultureInfo comparand = null;

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opEquality_Language_Language()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_Language_LanguageDiffers()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Language_LanguageSame()
        {
            Language obj = new Language("en");
            Language comparand = obj;

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_LanguageNull_Language()
        {
            Language obj = null;
            Language comparand = new Language("en");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Language_LanguageNull()
        {
            Language obj = new Language("en");
            Language comparand = null;

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opInequality_Language_Language()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_Language_LanguageDiffers()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Language_LanguageSame()
        {
            Language obj = new Language("en");
            Language comparand = obj;

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_LanguageNull_Language()
        {
            Language obj = null;
            Language comparand = new Language("en");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Language_LanguageNull()
        {
            Language obj = new Language("en");
            Language comparand = null;

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opLesserThan_Language_Language()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_Language_LanguageLesser()
        {
            Language obj = new Language("fr");
            Language comparand = new Language("en");

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_LanguageLesser_Language()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.True(obj < comparand);
        }

        [Fact]
        public void opLesserThan_Language_LanguageNull()
        {
            Language obj = new Language("en");
            Language comparand = null;

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_LanguageNull_Language()
        {
            Language obj = null;
            Language comparand = new Language("en");

            Assert.True(obj < comparand);
        }

        [Fact]
        public void opLesserThan_LanguageNull_LanguageNull()
        {
            Language obj = null;
            Language comparand = null;

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opGreaterThan_Language_Language()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_LanguageGreater_Language()
        {
            Language obj = new Language("fr");
            Language comparand = new Language("en");

            Assert.True(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_Language_LanguageGreater()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_Language_LanguageNull()
        {
            Language obj = new Language("en");
            Language comparand = null;

            Assert.True(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_LanguageNull_Language()
        {
            Language obj = null;
            Language comparand = new Language("en");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_LanguageNull_LanguageNull()
        {
            Language obj = null;
            Language comparand = null;

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opExplicit_CultureInfo_Language()
        {
            CultureInfo expected = new CultureInfo("en");
            CultureInfo actual = (CultureInfo)new Language("en");

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opExplicit_CultureInfo_LanguageInvariant()
        {
            CultureInfo expected = CultureInfo.InvariantCulture;
            CultureInfo actual = (CultureInfo)new Language(expected.Name);

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opExplicit_CultureInfo_LanguageNull()
        {
            CultureInfo expected = null;
            CultureInfo actual = (CultureInfo)(null as Language);

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opImplicit_CultureInfo_Language()
        {
            CultureInfo expected = new CultureInfo("en");
            CultureInfo actual = new Language("en");

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opImplicit_CultureInfo_LanguageInvariant()
        {
            CultureInfo expected = CultureInfo.InvariantCulture;
            CultureInfo actual = new Language(expected.Name);

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opImplicit_CultureInfo_LanguageNull()
        {
            CultureInfo expected = null;
            CultureInfo actual = null as Language;

            Assert.Equal<CultureInfo>(expected, actual);
        }

        [Fact]
        public void opExplicit_Language_CultureInfo()
        {
            Language expected = new Language("en");
            Language actual = (Language)new CultureInfo("en");

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opExplicit_Language_CultureInfoNull()
        {
            Language expected = null;
            Language actual = (Language)(null as CultureInfo);

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opImplicit_Language_CultureInfo()
        {
            Language expected = new Language("en");
            Language actual = new CultureInfo("en");

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opImplicit_Language_CultureInfoNull()
        {
            Language expected = null;
            Language actual = null as CultureInfo;

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opExplicit_Language_string()
        {
            Language expected = new Language("en");
            Language actual = (Language)"en";

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opExplicit_LanguageRegion_string()
        {
            Language expected = new Language("en-GB");
            Language actual = (Language)"en-GB";

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opExplicit_Language_stringNull()
        {
            Language expected = null;
            Language actual = (Language)(null as string);

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opImplicit_Language_string()
        {
            Language expected = new Language("en");
            Language actual = "en";

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opImplicit_LanguageRegion_string()
        {
            Language expected = new Language("en-GB");
            Language actual = "en-GB";

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opImplicit_Language_stringNull()
        {
            Language expected = null;
            Language actual = null as string;

            Assert.Equal<Language>(expected, actual);
        }

        [Fact]
        public void opExplicit_string_Language()
        {
            string expected = "en";
            string actual = (string)new Language(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opExplicit_string_LanguageNull()
        {
            string expected = null;
            string actual = (string)(null as Language);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opImplicit_string_Language()
        {
            string expected = "en";
            string actual = new Language(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opImplicit_string_LanguageNull()
        {
            string expected = null;
            string actual = null as Language;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_IsValid_string()
        {
            Assert.True(Language.IsValid("en"));
        }

        [Fact]
        public void op_IsValid_stringCulture()
        {
            Assert.True(Language.IsValid("en-GB"));
        }

        [Fact]
        public void op_IsValid_stringEmpty()
        {
            Assert.True(Language.IsValid(string.Empty));
        }

        [Fact]
        public void op_IsValid_stringInvalid()
        {
            Assert.False(Language.IsValid("not-a-valid-language"));
        }

        [Fact]
        public void op_IsValid_stringNull()
        {
            Assert.False(Language.IsValid(null as string));
        }

        [Fact]
        public void op_CompareTo_Language()
        {
            int expected = 1;
            int actual = new Language("en").CompareTo(null as Language);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_LanguageEqual()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            int expected = 0;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_LanguageGreater()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            int expected = -1;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_LanguageLesser()
        {
            Language obj = new Language("fr");
            Language comparand = new Language("en");

            int expected = 1;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_LanguageSame()
        {
            Language obj = new Language("en");

            int expected = 0;
            int actual = obj.CompareTo(obj);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_object()
        {
            int expected = 1;
            int actual = new Language("en").CompareTo(null as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectEqual()
        {
            Language obj = new Language("en");
            object comparand = new Language("en");

            int expected = 0;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectGreater()
        {
            Language obj = new Language("en");
            object comparand = new Language("fr");

            int expected = -1;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectLesser()
        {
            Language obj = new Language("fr");
            object comparand = new Language("en");

            int expected = 1;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectSame()
        {
            Language obj = new Language("en");

            int expected = 0;
            int actual = obj.CompareTo(obj as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectString()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => new Language("en").CompareTo("en" as object));
        }

        [Fact]
        public void op_Equals_LanguageEqual()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.True(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_LanguageUnequal()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.False(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_LanguageNull()
        {
            Assert.False(new Language("en").Equals(null as Language));
        }

        [Fact]
        public void op_Equals_LanguageSame()
        {
            Language obj = new Language("en");
            Language comparand = obj;

            Assert.True(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_object()
        {
            Language obj = new Language("en");
            Language comparand = new Language("en");

            Assert.True(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectDiffer()
        {
            Language obj = new Language("en");
            Language comparand = new Language("fr");

            Assert.False(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectSame()
        {
            Language obj = new Language("en");

            Assert.True(obj.Equals(obj as object));
        }

        [Fact]
        public void op_Equals_objectNull()
        {
            Assert.False(new Language("en").Equals(null as object));
        }

        [Fact]
        public void op_Equals_objectString()
        {
            Assert.False(new Language("en").Equals("en" as object));
        }

        [Fact]
        public void op_GetHashCode()
        {
            int expected = "en".GetHashCode();
            int actual = new Language("en").GetHashCode();

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_ToString()
        {
            string expected = "en";
            string actual = new Language(expected).ToString();

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_GetObjectData_SerializationInfoNull_StreamingContext()
        {
            StreamingContext context = new StreamingContext(StreamingContextStates.All);

            Assert.Throws<ArgumentNullException>(() => (new Language("en") as ISerializable).GetObjectData(null as SerializationInfo, context));
        }

        [Fact]
        public void op_GetObjectData_SerializationInfo_StreamingContext()
        {
            SerializationInfo info = new SerializationInfo(typeof(AbsoluteUri), new FormatterConverter());
            StreamingContext context = new StreamingContext(StreamingContextStates.All);

            string expected = "en";

            (new Language(expected) as ISerializable).GetObjectData(info, context);

            string actual = info.GetString("_value");

            Assert.Equal<string>(expected, actual);
        }
    }
}